/* Copyright (c) 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sohoappspot.sohosched.client.model;

import java.io.Serializable;
import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The RPC api available to the client. The asynchronous version that is used
 * directly by the client is {@link ServiceAsync}.
 * 
 * @author knorton@google.com (Kelly Norton)
 */
@RemoteServiceRelativePath("service")
public interface Service extends RemoteService {

	/**
	 * An exception that is thrown by the server whenever the current user is
	 * not logged in, or if the RPC requests an operation that cannot be carried
	 * out for the user (i.e. putting notes on someone else's surface).
	 */
	@SuppressWarnings("serial")
	static class AccessDeniedException extends Exception {
	}

	/**
	 * Encapsulates a response for
	 * {@link Service#addAuthorToSurface(String, String)}.
	 */
	@SuppressWarnings("serial")
	static class AddAuthorToSurfaceResult implements Serializable {
		private String authorName;

		private Date updatedAt;

		/**
		 * Constructs a new result. This constructor can only be invoked on the
		 * server.
		 * 
		 * @param authorName
		 *            the name of the author that was added to the surface
		 * @param updatedAt
		 *            the new last updated time for the surface
		 */
		public AddAuthorToSurfaceResult(String authorName, Date updatedAt) {
			assert !GWT.isClient();
			this.authorName = authorName;
			this.updatedAt = updatedAt;
		}

		/**
		 * Needed for RPC serialization.
		 */
		@SuppressWarnings("unused")
		private AddAuthorToSurfaceResult() {
		}

		/**
		 * The name of the {@link Author} that was added to the surface.
		 * 
		 * @return
		 */
		public String getAuthorName() {
			return authorName;
		}

		/**
		 * The new last updated time for the surface that was modified.
		 * 
		 * @return
		 */
		public Date getUpdatedAt() {
			return updatedAt;
		}
	}

	/**
	 * Encapsulates a response from
	 * {@link Service#createNote(String, int, int, int, int)}.
	 */
	@SuppressWarnings("serial")
	static class CreateObjectResult implements Serializable {
		private String key;

		private Date updateTime;

		/**
		 * Constructs a new result. This constructor can only be invoked on the
		 * server.
		 * 
		 * @param key
		 *            the key that was assigned to the new {@link Note}
		 * @param updateTime
		 *            the time assigned to {@link Note#getLastUpdatedAt()}
		 */
		public CreateObjectResult(String key, Date updateTime) {
			assert !GWT.isClient();
			this.key = key;
			this.updateTime = updateTime;
		}

		/**
		 * Needed for RPC serialization.
		 */
		@SuppressWarnings("unused")
		private CreateObjectResult() {
		}

		/**
		 * Returns the key that was assigned to the new {@link Note}.
		 * 
		 * @return
		 */
		public String getKey() {
			return key;
		}

		/**
		 * Returns the {@link Date} that was assigned to
		 * {@link Note#getLastUpdatedAt()} by the server.
		 * 
		 * @return
		 */
		public Date getUpdateTime() {
			return updateTime;
		}
	}

	/**
	 * Encapsulates a response from {@link Service#getNotes(String, String)}.
	 */
	@SuppressWarnings("serial")
	static class GetNotesResult implements Serializable {
		private String timestamp;

		private Note[] notes;

		/**
		 * Constructs a new result. This constructor can only be invoked on the
		 * server.
		 * 
		 * @param timestamp
		 *            an opaque timestamp
		 * @param notes
		 *            the list of notes to return
		 */
		public GetNotesResult(String timestamp, Note[] notes) {
			assert !GWT.isClient();
			this.timestamp = timestamp;
			this.notes = notes;
		}

		/**
		 * Needed for RPC serialization.
		 */
		@SuppressWarnings("unused")
		private GetNotesResult() {
		}

		/**
		 * Returns the notes that were returned by the server. This can be
		 * zero-length, but will not be null.
		 * 
		 * @return
		 */
		public Note[] getNotes() {
			return notes;
		}

		/**
		 * Returns an opaque timestamp that should be included in future calls
		 * to {@link Service#getNotes(String, String)}.
		 * 
		 * @return
		 */
		public String getTimestamp() {
			return timestamp;
		}
	}

	/**
	 * Encapsulates a response to {@link Service#getSurfaces(String)}.
	 */
	@SuppressWarnings("serial")
	static class GetSurfacesResult implements Serializable {
		private String timestamp;

		private Surface[] surfaces;

		/**
		 * Constructs a new result. This constructor can only be invoked on the
		 * server.
		 * 
		 * @param timestamp
		 *            an opaque timestamp
		 * @param surfaces
		 *            a list of surfaces for the current author
		 */
		public GetSurfacesResult(String timestamp, Surface[] surfaces) {
			assert !GWT.isClient();
			this.timestamp = timestamp;
			this.surfaces = surfaces;
		}

		/**
		 * Needed for RPC serialization.
		 */
		@SuppressWarnings("unused")
		private GetSurfacesResult() {
		}

		/**
		 * Returns a list of surfaces for the current author.
		 * 
		 * @return
		 */
		public Surface[] getSurfaces() {
			return surfaces;
		}

		/**
		 * Returns an opaque timestamp.
		 * 
		 * @return
		 */
		public String getTimestamp() {
			return timestamp;
		}
	}

	/**
	 * Encapsulates a response for {@link Service#getUserInfo()}.
	 */
	@SuppressWarnings("serial")
	static class UserInfoResult implements Serializable {
		private String userEmail;

		private String userNickname;

		private String logoutUrl;
		
		private String loginUrl;

		private Boolean isLoggedIn;
		
		private Boolean isAdmin;

		/**
		 * Constructs a new response. This constructor can only be invoked on
		 * the server.
		 * 
		 * @param author
		 *            the current author
		 * @param surface
		 *            the initially selected {@link Surface}
		 * @param logoutUrl
		 *            a url that can be used to log the current user out
		 */
		public UserInfoResult(String userEmail, String userNickname, String logoutUrl,String loginUrl, Boolean isLoggedIn, Boolean isAdmin) {
			assert !GWT.isClient();
			this.userEmail = userEmail;
			this.userNickname= userNickname;
			this.logoutUrl = logoutUrl;
			this.loginUrl = loginUrl;
			this.isLoggedIn = isLoggedIn;
			this.isAdmin = isAdmin;
		}

		/**
		 * Needed for RPC serialization.
		 */
		@SuppressWarnings("unused")
		private UserInfoResult() {
		}

		/**
		 * Returns the current author.
		 * 
		 * @return
		 */
		public String getUserEmail() {
			return userEmail;
		}

		/**
		 * Returns a url that can be used to log the author out.
		 * 
		 * @return
		 */
		public String getLogoutUrl() {
			return logoutUrl;
		}
		
		/**
		 * Returns a url that can be used to log the author in.
		 * 
		 * @return
		 */
		public String getLoginUrl() {
			return loginUrl;
		}

		public Boolean getIsLoggedIn() {
			return isLoggedIn;
		}		
		
		public Boolean getIsAdmin() {
			return isAdmin;
		}

		/**
		 * Returns the default surface for the author. This is the surface that
		 * will be selected when the application first loads.
		 * 
		 * @return
		 */
		public String getUserNickname() {
			return userNickname;
		}
	}

	/**
	 * Add an author to the author list of a surface.
	 * 
	 * @param surfaceKey
	 *            the key of the surface being modified
	 * @param email
	 *            the email address of the author being added
	 * @return a result object
	 * @throws AccessDeniedException
	 */
	AddAuthorToSurfaceResult addAuthorToSurface(String surfaceKey, String email)
			throws AccessDeniedException;

	/**
	 * Updates the content of a {@link Note}.
	 * 
	 * @param noteKey
	 *            they key of the note to modify
	 * @param content
	 *            the new content to assign
	 * @return the new last updated date for the note that was modified
	 * @throws AccessDeniedException
	 */
	Date changeNoteContent(String noteKey, String content)
			throws AccessDeniedException;

	/**
	 * Updates the position for a {@link Note}.
	 * 
	 * @param noteKey
	 *            the key of the note to modify
	 * @param x
	 *            the new x value
	 * @param y
	 *            the new y value
	 * @param width
	 *            the new width value
	 * @param height
	 *            the new height value
	 * @return the new last updated date for the note that was modified
	 * @throws AccessDeniedException
	 */
	Date changeNotePosition(String noteKey, int x, int y, int width, int height)
			throws AccessDeniedException;

	/**
	 * Creates a new {@link Note}.
	 * 
	 * @param surfaceKey
	 *            the key of the surface where this note will be created
	 * @param x
	 *            the x position for the new note
	 * @param y
	 *            the y position for the new note
	 * @param width
	 *            the width of the new note
	 * @param height
	 *            the height of the new note
	 * @return a result object
	 * @throws AccessDeniedException
	 */
	CreateObjectResult createNote(String surfaceKey, int x, int y, int width,
			int height) throws AccessDeniedException;

	/**
	 * Create a new {@link Surface}.
	 * 
	 * @param title
	 *            the title of the surface
	 * @return a result object
	 * @throws AccessDeniedException
	 */
	CreateObjectResult createSurface(String title) throws AccessDeniedException;

	/**
	 * Get all notes for the currently logged in author. <code>timestamp</code>
	 * is an opaque timestamp used by the server to optimize the set of results
	 * that are returned. Callers should pass a timestamp from
	 * {@link GetNotesResult#getTimestamp()}. For the initial call, or to simply
	 * receive the full set of notes, pass <code>null</code>.
	 * 
	 * @param surfaceKey
	 *            the surface to query
	 * @param timestamp
	 *            an opaque timestamp
	 * @return
	 * @throws AccessDeniedException
	 */
	GetNotesResult getNotes(String surfaceKey, String timestamp)
			throws AccessDeniedException;

	/**
	 * Get all the surfaces for the currently logged in author.
	 * <code>timestamp</code> is an opaque timestamp user by the server to
	 * optimize the number of results that are returned. Callers should pass a
	 * timestamp from {@link GetSurfacesResult#getTimestamp()}. For the initial
	 * call, or to simply receive the full set of surfaces, pass
	 * <code>null</code> .
	 * 
	 * @param timestamp
	 *            an opaque timestamp
	 * @return a result object
	 * @throws AccessDeniedException
	 */
	GetSurfacesResult getSurfaces(String timestamp)
			throws AccessDeniedException;

	/**
	 * Returns the information needed to load the application.
	 * 
	 * @return a result object
	 * @throws AccessDeniedException
	 */
	UserInfoResult getUserInfo() throws AccessDeniedException;
}
